/*
 *  vec3.h
 *  rayTracer
 *
 *  Created by Zachry Thayer on 10/6/09.
 *  Copyright 2009 __MyCompanyName__. All rights reserved.
 *
 */

#ifndef Vec3_h
#define Vec3_h

#include <math.h>
#include <iostream>

class Vec3
{
public:
	// Data
	float x, y, z;
	
	// Ctors
	//Vec3(Vec3 *V) : x(V.x), y(V.y), z(V.z){}
	Vec3( float InX, float InY, float InZ ) : x( InX ), y( InY ), z( InZ ){}
	Vec3( ) : x(0), y(0), z(0){}
	
	// Operator Overloads
	inline bool operator== (const Vec3& V2) const 
	{
		return (x == V2.x && y == V2.y && z == V2.z);
	}
	
	inline Vec3 operator+ (const Vec3& V2) const 
	{
		return Vec3( x + V2.x,  y + V2.y,  z + V2.z);
	}
	
	inline Vec3 operator+ (const float f) const
	{
		return Vec3( x + f,  y + f,  z + f);
	}
	
	inline Vec3 operator- (const Vec3& V2) const
	{
		return Vec3( x - V2.x,  y - V2.y,  z - V2.z);
	}
	
	inline Vec3 operator- (const float f) const
	{
		return Vec3( x - f,  y - f,  z - f);
	}
	
	inline Vec3 operator- ( ) const
	{
		return Vec3(-x, -y, -z);
	}
	
	inline Vec3 operator/ (float S ) const
	{
		float fInv = 1.0f / S;
		return Vec3 (x * fInv , y * fInv, z * fInv);
	}
	inline Vec3 operator/ (const Vec3& V2) const
	{
		return Vec3 (x / V2.x,  y / V2.y,  z / V2.z);
	}
	inline Vec3 operator* (const Vec3& V2) const
	{
		return Vec3 (x * V2.x,  y * V2.y,  z * V2.z);
	}
	inline Vec3 operator* (float S) const
	{
		return Vec3 (x * S,  y * S,  z * S);
	}
	
	inline void operator+= ( const Vec3& V2 )
	{
		x += V2.x;
		y += V2.y;
		z += V2.z;
	}
	inline void operator-= ( const Vec3& V2 )
	{
		x -= V2.x;
		y -= V2.y;
		z -= V2.z;
	}
	
	inline void print(void){
		std::cout << "V.x = " << x << " V.y = " << y << " V.z = " << z << std::endl;
	}
	
	//inline Vec3 operator= ( const Vec3& V2 )
	//{
	//	return Vec3(V2.x,V2.y,V2.z);
	//}
	
	inline float operator[] ( int i )
	{
		if ( i == 0 ) return x;
		else if ( i == 1 ) return y;
		else return z;
	}
	
	// Functions
	inline float dot( const Vec3 &V1 ) const
	{
		return V1.x*x + V1.y*y + V1.z*z;
	}
		
	inline Vec3 crossProduct( const Vec3 &V2 ) const
	{
		return Vec3(
					 y * V2.z  -  z * V2.y,
					 z * V2.x  -  x * V2.z,
					 x * V2.y  -  y * V2.x 	);
	}
	
	// Return vector rotated by the 3x3 portion of matrix m
	// (provided because it's used by bbox.cpp in article 21)
	Vec3 rotByMatrix( const float m[16] ) const
	{
		return Vec3( 
					  x*m[0] + y*m[4] + z*m[8],
					  x*m[1] + y*m[5] + z*m[9],
					  x*m[2] + y*m[6] + z*m[10] );
 	}
	
	// These require math.h for the sqrtf function
	float magnitude( ) const
	{
		return sqrtf( x*x + y*y + z*z );
	}
	
	float magnitudeSquared( ) const
	{
		return x*x + y*y + z*z;
	}
	
	float distance( const Vec3 &V1 ) const
	{
		return ( *this - V1 ).magnitude();	
	}
	
	inline void normalize()
	{
		float fMag = ( x*x + y*y + z*z );
		if (fMag == 0) {return;}
		
		float fMult = 1.0f/sqrtf(fMag);            
		x *= fMult;
		y *= fMult;
		z *= fMult;
		return;
	}
	
	inline Vec3 normal()
	{
		float fMag = ( x*x + y*y + z*z );
		if (fMag == 0) {return Vec3();}
		
		float fMult = 1.0f/sqrtf(fMag);            
		
		return Vec3(x * fMult, y *fMult, z * fMult);
	}
	
};

/*inline float operator * (const Vec3 &v1, const Vec3 &v2 ) {
	return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}*/

#endif